package com.zeny.express.framework.core.domain;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.RowBounds;

/**
 * 分页对象
 * 
 * @author zhuwei
 * @date 2013年8月17日 下午8:47:07
 */
public class Page<T> extends RowBounds {

	public final static String COUNT_ALIAS = "COUNT";
	
	public final static int PAGE_BEGIN = 1;

	/**
	 * 每页记录数
	 */
	private int pageSize;

	/**
	 * 当前页
	 */
	private int currentPage;

	/**
	 * 总页数
	 */
	private int totalPages;

	/**
	 * 总记录数
	 */
	private int totalRows;

	/**
	 * 是否计算汇总项
	 */
	private boolean totalCounted = true;

	/**
	 * 是否缓存使用合计
	 */
	private boolean totalCached = false;

	/**
	 * 数据
	 */
	private List<T> rows = Collections.emptyList();

	/**
	 * 排序Map
	 */
	private Map<String, String> orderMap = new LinkedHashMap<String, String>();

	/**
	 * 聚合Map
	 */
	private Map<String, String> aggregationMap = new LinkedHashMap<String, String>();

	/**
	 * 返回值
	 */
	private Map<String, Object> aggregationResult = new LinkedHashMap<String, Object>();

	/**
	 * 覆盖RowBounds构造函数
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午12:58:17
	 */
	public Page() {
		this.currentPage = PAGE_BEGIN;
		this.pageSize = Integer.MAX_VALUE;
	}

	/**
	 * 覆盖RowBounds构造函数
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午12:58:17
	 */
	public Page(int currentPage, int pageSize) {
		this.currentPage = currentPage;
		this.pageSize = pageSize;
	}

	/**
	 * 通过总记录数计算
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午1:02:22
	 * @param totalRows
	 */
	public void calculate(int totalRows) {
		// 设置总记录数
		this.totalRows = totalRows;

		// 设置总页数
		int totalPages = 0;

		if (totalRows == 0 || pageSize == 0) {
			totalPages = 0;
		} else {
			int r = totalRows % pageSize;
			totalPages = (totalRows - r) / pageSize;
			if (r > 0) {
				totalPages += 1;
			}
		}

		this.totalPages = totalPages;

		// 修正当前页数，小于零和大于总页数
		int oldCurrentPage = currentPage;
		if (oldCurrentPage <= 0 || totalRows == 0) {
			currentPage = 1;
		} else if (totalRows <= pageSize * oldCurrentPage) {
			if (totalRows > 0) {
				currentPage = (totalRows + pageSize - 1) / pageSize;
			}
		}

	}

	/**
	 * 重置获取offset方法
	 * 
	 * @author zhuwei
	 * @date 2013年8月18日 上午9:56:29
	 * @see org.apache.ibatis.session.RowBounds#getOffset()
	 */
	@Override
	public int getOffset() {
		return (currentPage - 1) * pageSize;
	}

	/**
	 * 重置获取offset方法
	 * 
	 * @author zhuwei
	 * @date 2013年8月18日 上午9:57:25
	 * @see org.apache.ibatis.session.RowBounds#getLimit()
	 */
	@Override
	public int getLimit() {
		return pageSize;
	}

	/**
	 * 增加聚合函数
	 * 
	 * <pre>
	 * 例如费用合计：["TOTAL_FEE", "SUM(FEE)"]
	 * </pre>
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午1:05:20
	 * @param name
	 * @param expression
	 */
	public void addAggregation(String name, String expression) {
		this.aggregationMap.put(name, expression);
	}

	/**
	 * 增加排序
	 * 
	 * <pre>
	 * 例如按版本号降序：["VERSION_NO", "DESC"]
	 * </pre>
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午1:34:01
	 * @param name
	 * @param order
	 */
	public void addOrder(String name, String order) {
		this.orderMap.put(name, order);
	}

	/**
	 * 是否首页
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午1:05:32
	 * @return
	 */
	public boolean isFirstPage() {
		return currentPage <= 1;
	}

	/**
	 * 是否最后一页
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午1:05:49
	 * @return
	 */
	public boolean isLastPage() {
		return currentPage >= totalPages || totalPages == 0;
	}

	/**
	 * 重载toString方法
	 * 
	 * @author zhuwei
	 * @date 2013年8月19日 下午1:04:56
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("\ntotalPages: " + totalPages);
		sb.append(", pageSize: " + pageSize);
		sb.append(", currentPage: " + currentPage);
		sb.append(", totalRows: " + totalRows);

		if (null != rows && !rows.isEmpty()) {
			sb.append(", rows size: " + rows.size());
		}

		for (Map.Entry<String, Object> entry : aggregationResult.entrySet()) {
			sb.append(", " + entry.getKey() + ": " + entry.getValue());
		}

		return sb.toString();
	}

	/**
	 * @return pageSize
	 */
	public int getPageSize() {
		return pageSize;
	}

	/**
	 * @return currentPage
	 */
	public int getCurrentPage() {
		return currentPage;
	}

	/**
	 * @return totalPages
	 */
	public int getTotalPages() {
		return totalPages;
	}

	/**
	 * @return totalRows
	 */
	public int getTotalRows() {
		return totalRows;
	}

	/**
	 * @return data
	 */
	public List<T> getRows() {
		return rows;
	}

	/**
	 * @param data
	 */
	public void setRows(List<T> rows) {
		this.rows = rows;
	}

	/**
	 * @return orderMap
	 */
	public Map<String, String> getOrderMap() {
		return orderMap;
	}

	/**
	 * @return aggregationMap
	 */
	public Map<String, String> getAggregationMap() {
		return aggregationMap;
	}

	/**
	 * @return aggregationResult
	 */
	public Map<String, Object> getAggregationResult() {
		return aggregationResult;
	}

	/**
	 * @param aggregationResult
	 */
	public void setAggregationResult(Map<String, Object> aggregationResult) {
		this.aggregationResult = aggregationResult;
	}

	/**
	 * @param pageSize
	 */
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	/**
	 * @param currentPage
	 */
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	/**
	 * @return totalCounted
	 */
	public boolean isTotalCounted() {
		return totalCounted;
	}

	/**
	 * @param totalCounted
	 */
	public void setTotalCounted(boolean totalCounted) {
		this.totalCounted = totalCounted;
	}

	/**
	 * @return totalCached
	 */
	public boolean isTotalCached() {
		return totalCached;
	}

	/**
	 * @param totalCached
	 */
	public void setTotalCached(boolean totalCached) {
		this.totalCached = totalCached;
	}

}
